// Thud - a dynamic object-oriented language
// Copyright (C) 2009,2010 David H. Hovemeyer <david.hovemeyer@gmail.com>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

/*
 * RecursiveDescenceClassVisitor.cpp
 *
 *  Created on: Dec 6, 2009
 *      Author: dhovemey
 */

#include "util/String.h"
#include "vm/Class.h"
#include "vm/ConstantPool.h"
#include "vm/Method.h"
#include "vm/ClassFormatException.h"
#include "vm/RecursiveDescentClassVisitor.h"

RecursiveDescentClassVisitor::RecursiveDescentClassVisitor()
{
}

RecursiveDescentClassVisitor::~RecursiveDescentClassVisitor()
{
}

void RecursiveDescentClassVisitor::visitClass(Class *cls)
{
	visitConstantPool(cls->getConstantPool());

	for (Class::FieldList::iterator i = cls->getFields().begin(); i != cls->getFields().end(); i++) {
		visitField(*i);
	}

	for (Class::MethodList::iterator i = cls->getMethods().begin(); i != cls->getMethods().end(); i++) {
		visitMethod(*i);
	}
}

void RecursiveDescentClassVisitor::visitConstantPool(ConstantPool *cp)
{
	for (uint32_t i = 0; i < cp->getNumConstants(); i++) {
		Constant *c = cp->getConstant((uint16_t) i);
		c->accept(this);
	}
}

void RecursiveDescentClassVisitor::visitConstantString(ConstantString *c)
{
}

void RecursiveDescentClassVisitor::visitConstantSymbol(ConstantSymbol *c)
{
}

void RecursiveDescentClassVisitor::visitConstantClass(ConstantClass *c)
{
}

void RecursiveDescentClassVisitor::visitConstantI32(ConstantInt32 *c)
{
}

void RecursiveDescentClassVisitor::visitConstantBoolean(ConstantBoolean *c)
{

}

void RecursiveDescentClassVisitor::visitField(Field *field)
{
}

void RecursiveDescentClassVisitor::visitMethod(Method *method)
{
	// Disassemble instructions

	const uint8_t *code = method->getCode();
	int numBytes = method->getNumBytes();

	for (int offset = 0; offset < numBytes;) {
		uint16_t insOffset = uint16_t(offset);

		int8_t opcode = code[offset];
		if (opcode < 0 || opcode >= OP_NUM_OPCODES) {
			throw ClassFormatException(L"Invalid opcode");
		}
		offset++;

		int flags = ::opcodeGetFlags((Opcode) opcode);

		if (flags == 0) {
			visitInstruction(insOffset, (Opcode) opcode);
		} else if (flags == OP_FLAG_BRANCH) {
			uint16_t target = unpackCodeShort(offset, code, numBytes);
			visitBranchInstruction(insOffset, (Opcode) opcode, target);
		} else if (flags == OP_FLAG_CP_REF) {
			uint16_t cpIndex = unpackCodeShort(offset, code, numBytes);
			visitCPInstruction(insOffset, (Opcode) opcode, cpIndex);
		} else if (flags == OP_FLAG_I8_CONST) {
			int8_t i8 = code[offset++];
			visitI8Instruction(insOffset, (Opcode) opcode, i8);
		} else if (flags == (OP_FLAG_CP_REF | OP_FLAG_I8_CONST)) {
			uint16_t cpIndex = unpackCodeShort(offset, code, numBytes);
			int8_t i8 = code[offset++];
			visitCPI8Instruction(insOffset, (Opcode) opcode, cpIndex, i8);
		} else {
			std::wstring msg(L"Invalid opcode flags ");
			msg += String::asWString(flags);
			msg += L" for opcode ";
			msg += opcodeGetName((Opcode) opcode);
			throw Exception(msg);
		}
	}
}

void RecursiveDescentClassVisitor::visitInstruction(uint16_t offset, Opcode opcode)
{
}

void RecursiveDescentClassVisitor::visitCPInstruction(uint16_t offset, Opcode opcode, uint16_t cpIndex)
{
}

void RecursiveDescentClassVisitor::visitI8Instruction(uint16_t offset, Opcode opcode, int8_t i8)
{
}

void RecursiveDescentClassVisitor::visitCPI8Instruction(uint16_t offset, Opcode opcode, uint16_t cpIndex, int8_t i8)
{
}

void RecursiveDescentClassVisitor::visitBranchInstruction(uint16_t offset, Opcode opcode, uint16_t branchOffset)
{
}

uint16_t RecursiveDescentClassVisitor::unpackCodeShort(int &offset, const uint8_t *code, int numBytes)
{
	if (offset + 2 > numBytes) {
		throw ClassFormatException(L"Unexpected end of file");
	}
	uint16_t value;
	value = code[offset++] << 8;
	value |= code[offset++] & 0xFF;
	return value;
}
